import java.util.*;

/**
 * @author LKQ
 * @date 2022/2/25 23:09
 * @description 拓扑排序 + 动态规划
 */
public class FormalSolution {
    public static void main(String[] args) {
        int[][] relations = {{1,5},{2,5},{3,5},{3,4},{4,5}};
        int[] time = {1,2,3,4,5};
        FormalSolution solution = new FormalSolution();
        solution.minimumTime(5, relations, time);
    }
    public int minimumTime(int n, int[][] relations, int[] time) {
        // 每个节点的入度
        int[] inDegree = new int[n + 1];
        // dp[i] 为第i门课结束的最少月份，dp[i] = max{dp[j]} + time[i-1], j为i的所有前导课程,
        int[] dp = new int[n + 1];
        List<Integer>[] graph = new List[n + 1];
        for (int i = 1; i <= n; i++) {
            graph[i] = new ArrayList<>();
        }
        // 初始化
        for (int[] edge : relations) {
            int u = edge[0];
            int v = edge[1];
            // 完成u才能下一门课程
            graph[u].add(v);
            inDegree[v]++;
        }
        // 保存没有先修课的课程
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 1; i <= n; i++) {
            if (inDegree[i] == 0) {
                // 入度为0，代表没有先修课
                queue.add(i);
                dp[i] = time[i - 1];
            }
        }
        while (!queue.isEmpty()) {
            // 没有先修课的课程
            int index = queue.poll();
            // 对于当前index的所有下一门课程，修改下一门课程最少完成月份
            for (int next : graph[index]) {
                dp[next] = Math.max(dp[next], dp[index] + time[next - 1]);
                if (--inDegree[next] == 0) {
                    // 下一门课程的入度减一，如果到达零，那么其他节点全部遍历完全，将该节点加入，探索是否有next课程。
                    queue.add(next);
                }
            }
        }
        int ans = 0;
        for (int i = 1; i < n + 1; i++) {
            ans = Math.max(dp[i], ans);
        }
        return ans;
    }
}
